# coding: utf-8
'''
Created on 23 mai 2013

@author: Nils Amiet
'''

class PolarityCounter:
    
    polarityCounts = {}
    RECEIVED = "recv"
    SENT = "sent"
    AVERAGE = "avg"
    NDI = -1 # network disagreement index
    
    def __init__(self, replies):
        '''
        Replies: a list of replies with the attributes "from", "to" and "polarity"
        '''
        self.replies = replies
        self.edges = []
        self.countPolarities()
        self.computeAveragePolarities()
        self.computeNDI()
        
    def countPolarities(self):
        for reply in self.replies:
            fromUser = reply["from"]
            toUser = reply["to"]
            polarity = reply["polarity"]
            # negative polarity becomes 0 and positive becomes 1
            polarity = 0 if polarity <= 0 else 1
            
            try:
                fromUserCounts = self.polarityCounts[fromUser][self.SENT]
            except KeyError:
                self.polarityCounts[fromUser] = {self.RECEIVED : {}, self.SENT: {}, self.AVERAGE: None}
                fromUserCounts = self.polarityCounts[fromUser][self.SENT]
                
            try:
                toUserCounts = self.polarityCounts[toUser][self.RECEIVED]
            except KeyError:
                self.polarityCounts[toUser] = {self.RECEIVED : {}, self.SENT: {}, self.AVERAGE: None}
                toUserCounts = self.polarityCounts[toUser][self.RECEIVED]
            
            try:
                fromUserCounts[polarity] += 1
            except:
                fromUserCounts[polarity] = 1
                
            try:
                toUserCounts[polarity] += 1
            except:
                toUserCounts[polarity] = 1
    
    def computeAveragePolarities(self):        
        for user, userCounts in self.polarityCounts.items():
            try:
                receivedPositive = userCounts[self.RECEIVED][1]
            except:
                receivedPositive = 0
            try:
                receivedNegative = userCounts[self.RECEIVED][0]
            except:
                receivedNegative = 0
            try:
                sentPositive = userCounts[self.SENT][1]
            except:
                sentPositive = 0
            try:
                sentNegative = userCounts[self.SENT][0]
            except:
                sentNegative = 0
            try:
                recv = (receivedPositive - receivedNegative) / float(receivedPositive + receivedNegative)
            except:
                pass # user never received a message
            try:
                sent = (sentPositive - sentNegative) / float(sentPositive + sentNegative)
            except:
                pass # user never sent a message
            try:
                userCounts[self.AVERAGE] = abs(recv - sent)
            except:
                pass # user never received or sent a message
            
    def computeNDI(self):
        self.computeEdges()
        
        sumNDI = 0
        for edge in self.edges:
            weight = 1
            firstUser = edge["from"]
            secondUser = edge["to"]
            try:
                firstUserOpinion = self.polarityCounts[firstUser][self.AVERAGE] / float(2)
            except:
                firstUserOpinion = 0
            
            try:
                secondUserOpinion = self.polarityCounts[secondUser][self.AVERAGE] / float(2)
            except:
                secondUserOpinion = 0
                        
            increment = weight * ((firstUserOpinion - secondUserOpinion)**2)
            sumNDI += increment
                        
        self.NDI = sumNDI
    
    def computeEdges(self):
        for reply in self.replies:
            if not self.contains(reply, self.edges):
                self.edges += [reply]
                
    def contains(self, reply, edges):
        for edge in edges:
            if self.isSameMessage(reply, edge):
                return True
        return False
        
    def isSameMessage(self, reply, reply2):
        return reply["from"] == reply2["from"] and reply["to"] == reply2["to"] or reply["from"] == reply2["to"] and reply["to"] == reply2["from"]
            
    def polarityDifferenceRanking(self):
        users = {user: userCounts[self.AVERAGE] for user, userCounts in self.polarityCounts.items() if not userCounts[self.AVERAGE] == None}
        ranking = sorted(users.items(), key=lambda x: x[1], reverse=True)
        return ranking